<?php
/**
 * | 节程 [ 节程赋能开发者，助力企业发展 ]
 * +----------------------------------------------------------------------
 *  | Copyright (c) 2020~2029 温州惊蛰网络科技有限公司 All rights reserved.
 * +----------------------------------------------------------------------
 *  | Licensed 节程并不是自由软件，未经许可不能去掉节程相关版权
 * +----------------------------------------------------------------------
 */


namespace app\command;

use think\console\Input;
use think\console\Output;
use think\facade\Db;
use WePay\Refund;
use app\index\util\Redis;
use Psr\Log\InvalidArgumentException;

class Group extends BaseCommand
{
    private $commodityId;
    private $redis;


    private function backInventory($num, int $skuId = null, $mid)
    {
        if (empty($this->commodity['has_sku'])) {
            Db::name('commodity')->where('id', $this->commodityId)->dec('sell', $num)->update();
            $key = "COMMODITY:" . $this->commodityId . ":SELL";
            $data = [];
//            $price = $this->redis->lPop($this->checkRedisKey($key,$mid));
            $da = ["sell_price" => $this->commodity['sell_price'], "level_price" => Db::name("commodity")->find($this->commodityId)['level_price']];
            $price = json_encode($da);
            $data = array_pad($data, $num, $price);
            $this->redis->lPush($this->checkRedisKey($key, $mid), ...$data);
        } else {
            Db::name('commodity')->where('id', $this->commodityId)->dec('sell', $num)->update();
            Db::name('sku_inventory')->where(['sku_id' => $skuId])->dec('sell', $num)->update();
            $key = "COMMODITY:" . $this->commodityId . ":SKU:" . $skuId . ":SELL";
            $data = [];
//            $price = $this->redis->lPop($this->checkRedisKey($key,$mid));
            $da = ["sell_price" => $this->commodity['sell_price'], "level_price" => Db::name("commodity")->find($this->commodityId)['level_price']];
            $price = json_encode($da);
            $data = array_pad($data, $num, $price);
            $this->redis->lPush($this->checkRedisKey($key, $mid), ...$data);
        }
        return true;
    }

    private function checkRedisKey($key, $mid)
    {
        return "MALL:" . $mid . ":" . $key;
    }

    protected function configure()
    {
        // 指令配置
        $this->setName('group')
            ->setDescription('拼团');
    }
    protected function execute(Input $input, Output $output){
        $this->setDb($input, $output);
    }

    /**
     * 开始&结束活动
     * @param $now
     * @throws
     */
    public function setGroup($now)
    {
        // 开始活动
        $begin_group = Db::name('group')
            ->field('id')
            ->where('status', 0)
            ->whereTime('start_time', '<', $now)
            ->select()->toArray();
        $begin_ids = array_column($begin_group, "id");
        Db::name('group')
            ->where('id', 'in', $begin_ids)
            ->update(['status' => 1]);
        Db::name('group_commodity')
            ->where('group_id', 'in', $begin_ids)
            ->update(['status' => 1]);
        // 结束活动
        $over_group = Db::name('group')
            ->field('id')
            ->where('status', 1)
            ->whereTime('end_time', '<', $now)
            ->select()->toArray();
        $over_ids = array_column($over_group, "id");
        Db::name('group')
            ->where('id', 'in', $over_ids)
            ->update(['status' => 2]);
        Db::name('group_commodity')
            ->where('group_id', 'in', $over_ids)
            ->update(['status' => 2]);
    }


    /**
     * 开始结束秒杀
     * @param $now 时间
     * @throws
     */
    public function setSeckill($now)
    {
        // 开始活动
        $begin_group = Db::name('seckill')
            ->field('id')
            ->where('status', 0)
            ->whereTime('start_time', '<', $now)
            ->select()->toArray();
        $begin_ids = array_column($begin_group, "id");
        Db::name('seckill')
            ->where('id', 'in', $begin_ids)
            ->update(['status' => 1]);
        Db::name('seckill_commodity')
            ->where('seckill_id', 'in', $begin_ids)
            ->update(['status' => 1]);
        // 结束活动
        $over_group = Db::name('seckill')
            ->field('id')
            ->where('status', 1)
            ->whereTime('end_time', '<', $now)
            ->select()->toArray();
        $over_ids = array_column($over_group, "id");
        Db::name('seckill')
            ->where('id', 'in', $over_ids)
            ->update(['status' => 2]);
        Db::name('seckill_commodity')
            ->where('seckill_id', 'in', $over_ids)
            ->update(['status' => 2]);
    }

    /**
     * 开始结束预售
     * @param $now 时间
     * @throws
     */
    public function setPresell($now)
    {
        // 开始活动
        $begin_group = Db::name('presell')
            ->field('id')
            ->where('status', 0)
            ->whereTime('start_time', '<', $now)
            ->select()->toArray();
        $begin_ids = array_column($begin_group, "id");
        Db::name('presell')
            ->where('id', 'in', $begin_ids)
            ->update(['status' => 1]);
        Db::name('presell_commodity')
            ->where('presell_id', 'in', $begin_ids)
            ->update(['status' => 1]);
        // 结束活动
        $over_group = Db::name('presell')
            ->field('id')
            ->where('status', 1)
            ->whereTime('end_time', '<', $now)
            ->select()->toArray();
        $over_ids = array_column($over_group, "id");
        Db::name('presell')
            ->where('id', 'in', $over_ids)
            ->update(['status' => 2]);
        Db::name('presell_commodity')
            ->where('presell_id', 'in', $over_ids)
            ->update(['status' => 2]);
    }

    /**
     * 充值奖励
     * @param $now
     * @throws
     */
    public function setActivityRecharge($now)
    {
        // 开始活动
        $begin_group = Db::name('activity')
            ->field('id')
            ->where('status', 0)
            ->where('type', 1)
            ->whereTime('start_time', '<', $now)
            ->select()->toArray();
        $begin_ids = array_column($begin_group, "id");
        Db::name('activity')
            ->where('id', 'in', $begin_ids)
            ->update(['status' => 1]);

        Db::name('activity_recharge')
            ->where('aid', 'in', $begin_ids)
            ->update(['status' => 1]);
        // 结束活动
        $over_group = Db::name('activity')
            ->field('id')
            ->where('status', 1)
            ->where('type', 1)
            ->whereTime('end_time', '<', $now)
            ->select()->toArray();
        $over_ids = array_column($over_group, "id");

        Db::name('activity')
            ->where('id', 'in', $over_ids)
            ->update(['status' => 2]);
        Db::name('activity_recharge')
            ->where('aid', 'in', $over_ids)
            ->update(['status' => 2]);
    }

    /**
     * 结束拼团
     * @param $now
     * @throws
     */
    public function setGroupCommodity($now)
    {
        $over_gc = Db::name('group_commodity')
            ->field('id')
            ->where('status', 1)
            ->whereTime('end_time', '<', $now)
            ->select()
            ->toArray();
        $over_ids = array_column($over_gc, "id");
        Db::name('group_commodity')
            ->where('id', 'in', $over_ids)
            ->update(['status' => 2]);
    }

    /**
     * 结束秒杀
     * @param $now
     * @throws 
     */
    public function setSeckillCommodity($now)
    {
        $over_gc = Db::name('seckill_commodity')
            ->field('id')
            ->where('status', 1)
            ->whereTime('end_time', '<', $now)
            ->select()
            ->toArray();
        $over_ids = array_column($over_gc, "id");
        Db::name('seckill_commodity')
            ->where('id', 'in', $over_ids)
            ->update(['status' => 2]);
    }

    /**
     * 结束预售
     * @param $now
     * @throws
     */
    public function setPresellCommodity($now)
    {
        $over_gc = Db::name('presell_commodity')
            ->field('id')
            ->where('status', 1)
            ->whereTime('end_time', '<', $now)
            ->select()
            ->toArray();
        $over_ids = array_column($over_gc, "id");
        Db::name('presell_commodity')
            ->where('id', 'in', $over_ids)
            ->update(['status' => 2]);
    }

    /**
     * 处理拼团中
     * @param $now
     * @throws
     */
    public function setCollage($now, $gc_id = 0, $collage_id = 0)
    {
        $where = ['status' => 1];
        if ($gc_id > 0) {
            $where = array_merge($where, ['gc_id' => $gc_id]);
        }
        if ($collage_id > 0) {
            $where = array_merge($where, ['id' => $collage_id]);
        }
        $collages = Db::name('collage')->where($where)->select();
        foreach ($collages as $key => $value) {
            // 拼团成功
            if ($value['success_num'] == $value['num']) {
                Db::name('collage')->where('id', $value['id'])->update(['status' => 2]);
                $this->decStock($value);
                unset($collages[$key]);
            }
        }
        // 到期截团
        foreach ($collages as $key => $value) {
            // 截止拼团并退款
            if ($value['end_time'] < $now) {
                $check_stock = $this->checkStock($value);

                // 虚拟拼团
                $surplus = $value['success_num'] - $value['num'];
                $virtual_success = Db::name('group_commodity')->where('id', $value['gc_id'])->value('virtual_success');

                if (!empty($virtual_success) && $virtual_success != 0 && ($virtual_success >= $surplus && $surplus > 0) && $check_stock) {
                    for ($i = 1; $i <= $surplus; $i++) {
                        $user = [1, '/people/'.rand(1, 200).".jpg"];
                        $create[$i] = [
                            'mall_id' => $value['mall_id'],
                            'gc_id' => $value['gc_id'],
                            'collage_id' => $value['id'],
                            'commodity_id' => $value['commodity_id'],
                            'sku_id' => $value['sku_id'],
                            'create_time' => $now,
                            'user_id' => json_encode($user),
                            'is_robot' => 1
                        ];
                    }
                    Db::name('collage_item')->insertAll($create);
                    Db::name('collage')->where('id', $value['id'])->update(['status' => 2]);
                    $this->decStock($value);
                } else {
                    $oc_ids = [$value['oc_id']];
                    $items = Db::name("collage_item")->where('collage_id', $value['id'])->select();
                    if (count($items) > 0) {
                        $items = $items->toArray();
                        $oc_ids = array_column($items, 'oc_id');
                        array_push($oc_ids, $value['oc_id']);
                    }
                    $ocs = Db::name('order_commodity')->alias('a')->join('order b', 'a.order_id=b.id')->where('a.id', 'in', $oc_ids)->select()->toArray();
                    foreach ($ocs as $ok => $ov) {
                        // 支付方式 1-余额 2-微信 3-支付宝 4-后台支付
                        switch ($ov['pay_id']) {
                            case 1:
                                Db::name('user_cash')->where('user_id', $ov['user_id'])->inc("total", $ov['money'])->update();
                                Db::name('user_cash')->where('user_id', $ov['user_id'])->dec("expense", $ov['money'])->update();
                                break;
                            case 2:

                                try {
                                    $refund = Db::name("configuration")->where(['type' => "mallPayMode", 'mall_id' => $ov['mall_id']])->find();
                                    $configuration = json_decode($refund['configuration'], true);
                                    $config = Db::name('pay_mode')->find($configuration['wechat']['wx_pay_mode_id']);
                                    $configuration = json_decode($config['configuration'], true);
                                    $data = [
                                        "appid" => $configuration['AppId'],
                                        "mch_id" => $configuration['MchId'],
                                        "mch_key" => $configuration['APIKEY'],
                                        "ssl_key" => root_path(). "runtime/" . $config['wxkey'],
                                        "ssl_cer" => root_path(). "runtime/" . $config['cert']
                                    ];
                                    if ($config['type'] == 2) {
                                        $data['sub_appid'] = $configuration['M_AppId'] ?? '';
                                        $data['sub_mch_id'] = $configuration['M_MchId'] ?? '';
                                    }
                                    $option = [
                                        "out_trade_no" => $ov['unified_order_no'],
                                        "out_refund_no" => "refund_". $ov['unified_order_no'],
                                        "total_fee" => bcmul((string)$ov['money'], (string)100, 0),
                                        "refund_fee" => bcmul((string)$ov['money'], (string)100, 0),
                                    ];
                                    $refund = new Refund($data);
                                    $res = $refund->create($option);
                                } catch (\Exception $e) {

                                }

                                break;
                        }
                        $total = Db::name('user_cash')->where('user_id', $ov['user_id'])->value('total');
                        Db::name('recharge_record')->insert([
                            'mall_id' => $value['mall_id'],
                            'user_id' => $ov['user_id'],
                            'base_in' => $ov['base_in'],
                            'source_type' => 6,
                            'source' => "拼团退款",
                            'is_online' => 0,
                            'type' => 0,
                            'card' => '{}',
                            "money" => $ov['money'],
                            "service_charge" => 0,
                            "trade" => $ov['unified_order_no'],
                            "pay_no" => "",
                            'new_cash' => $total + $ov['money'],
                            'old_cash' => $total,
                            "status" => 1,
                            "create_time" => date('Y-m-d H:i:s'),
                            "update_time" => date('Y-m-d H:i:s'),
                        ]);
                    }

                    $update = ['status' => 11, 'after_type' => 1];
                    $ids = array_column($ocs, 'order_id');
                    Db::name('order')->where('id', 'in', $ids)->update($update);
                    Db::name('order_commodity')->where('id', 'in', $oc_ids)->update($update);
                    Db::name('agent_bill_temporary')
                        ->where('order_id', 'IN', $ids)
                        ->delete();
                    Db::name('order_agent_profit')
                        ->where('order_id', 'IN', $ids)
                        ->delete();
                    $orders = Db::name('order_commodity')
                        ->where('order_id', 'IN', $ids)
                        ->where('a.mall_id', $value['mall_id'])
                        ->alias('a')
                        ->join('commodity c', 'a.commodity_id = c.id', 'LEFT')
                        ->join('sku_inventory s', 'a.sku_id = s.sku_id', 'LEFT')
                        ->field('a.order_id,a.mall_id,a.commodity_id,a.count,(CASE WHEN c.has_sku = 1 THEN s.sell_price ELSE c.sell_price END) as price ,a.sku_id,c.inventory_type,a.status')
                        ->select();
                    foreach ($orders as $v) {
                        if (in_array($v['inventory_type'], [1, 2]) || (in_array($v['inventory_type'], [3]) && in_array($v['status'], [2, 3, 7]))) {
                            $this->redis = Redis::getInstance();
                            $commodityData = $this->redis->get($this->checkRedisKey('COMMODITY:' . $v['commodity_id'], $v['mall_id']));
                            if (empty($commodityData)) {
                                throw new InvalidArgumentException("商品数据不存在", HTTP_NOTACCEPT);
                            }
                            $this->commodity = json_decode($commodityData, true);
                            $this->commodityId = $v['commodity_id'];
                            $this->backInventory($v['count'],  $v['sku_id'], $v['mall_id']);
                        }
                    }

                    Db::name('collage')->where('id', $value['id'])->update(['status' => 11]);
                    $this->incStock($value);
                }
            }
        }

    }

    /**
     * 库存
     * @param $value
     * @return mixed
     * @throws
     */
    public function checkStock($value)
    {
        $flag = true;
        if (is_null($value['sku_id'])) {
            $commodity = Db::name('group_commodity')
                ->field("activity_stock")
                ->where('id', $value['gc_id'])
                ->find();
        } else {
            $commodity = Db::name('group_commodity_sku')
                ->field("activity_stock")
                ->where('gc_id', $value['gc_id'])
                ->where('sku_id', $value['sku_id'])
                ->find();
        }
        $stock = $commodity['activity_stock'];
        $count = Db::name('order_commodity')->find($value['oc_id'])['count'];
        $items_count = Db::name('collage_item')->alias('a')->join('order_commodity b', 'a.oc_id = b.id' )->where('a.collage_id', $value['id'])->count('b.count');

        if ($stock < ($count + $items_count)) {
            $flag = false;
        }
        return $flag;
    }

    /**
     * 减库存
     * @param $value
     * @throws
     */
    public function decStock($value)
    {
        $num = Db::name('order_commodity')->find($value['oc_id'])['count'];
        // 减拼团库存
        if (is_null($value['sku_id'])) {
            Db::name('group_commodity')
                ->where('id', $value['gc_id'])
                ->dec("activity_stock", $num)->update();
        } else {
            Db::name('group_commodity_sku')
                ->where('gc_id', $value['gc_id'])
                ->where('sku_id', $value['sku_id'])
                ->dec("activity_stock", $num)->update();
        }
    }

    /**
     * 加库存
     * @param $value
     * @throws
     */
    public function incStock($value)
    {
        $num = Db::name('order_commodity')->find($value['oc_id'])['count'];
        // 拼团库存
        if (is_null($value['sku_id'])) {
            Db::name('group_commodity')
                ->where('id', $value['gc_id'])
                ->inc("activity_stock", $num)->update();
        } else {
            Db::name('group_commodity_sku')
                ->where('gc_id', $value['gc_id'])
                ->where('sku_id', $value['sku_id'])
                ->inc("activity_stock", $num)->update();
        }
    }



    protected function executeAction(Input $input, Output $output)
    {
        $now = date("Y-m-d H:i:s", time());
        // 拼团
        $this->setGroup($now);
        $this->setGroupCommodity($now);
        $this->setCollage($now);
        // 秒杀
        $this->setSeckill($now);
        $this->setSeckillCommodity($now);
        // 预售
        $this->setPresell($now);
        $this->setPresellCommodity($now);
        // 充值奖励
        $this->setActivityRecharge($now);
    }

}